﻿// Copyright (c)  MOKEYISH. All rights reserved.
// Licensed under the MIT License, See License.txt in the project root for license information.

using System.Linq;
using NSQL.Builder;
using NSQL.Expressions;
using NSQL.Expressions.Functions;
using NSQL.Statements;
using NSQL.Statements.SelectStatements;

namespace NSQL
{
    public static class Static
    {
        public static ColumnExpression Column(string columnName) => columnName;
        public static ColumnExpression Column(int columnId) => new ColumnExpression(columnId);
        public static NowFunction Now() => NowFunction.Instance;

        public static ToCharFunction ToChar(IValueExpression expression, IStringExpression formatter)
        {
            return new ToCharFunction(expression, formatter);
        }

        public static ToCharFunction ToChar(IValueExpression expression, StringExpression formatter)
        {
            return new ToCharFunction(expression, formatter);
        }

        public static ToNumberFunction ToNumber(IValueExpression expression, IStringExpression formatter)
        {
            return new ToNumberFunction(expression, formatter);
        }

        public static ToNumberFunction ToNumber(IValueExpression expression, StringExpression formatter)
        {
            return new ToNumberFunction(expression, formatter);
        }

        public static ToNumberFunction ToNumber(IValueExpression expression)
        {
            return new ToNumberFunction(expression);
        }

        public static ToNumberFunction ToNumber(StringExpression expression, StringExpression formatter)
        {
            return new ToNumberFunction(expression, formatter);
        }

        public static ToNumberFunction ToNumber(StringExpression expression, IStringExpression formatter)
        {
            return new ToNumberFunction(expression, formatter);
        }

        public static ToNumberFunction ToNumber(StringExpression expression)
        {
            return new ToNumberFunction(expression);
        }

        public static SumFunction Sum(IValueExpression expression, AggregateType type = AggregateType.None)
        {
            return new SumFunction(expression, type);
        }

        public static SumFunction Sum(ColumnExpression expression, AggregateType type = AggregateType.None)
        {
            return new SumFunction(expression, type);
        }

        public static StdDevFunction StdDev(IValueExpression expression)
        {
            return new StdDevFunction(expression);
        }

        public static StdDevFunction StdDev(ColumnExpression expression)
        {
            return new StdDevFunction(expression);
        }

        public static VarianceFunction Variance(IValueExpression expression)
        {
            return new VarianceFunction(expression);
        }

        public static VarianceFunction Variance(ColumnExpression expression)
        {
            return new VarianceFunction(expression);
        }

        public static AvgFunction Avg(IValueExpression expression, AggregateType type = AggregateType.None)
        {
            return new AvgFunction(expression, type);
        }

        public static AvgFunction Avg(ColumnExpression expression, AggregateType type = AggregateType.None)
        {
            return new AvgFunction(expression, type);
        }

        public static MaxFunction Max(IValueExpression expression, AggregateType type = AggregateType.None)
        {
            return new MaxFunction(expression, type);
        }

        public static MaxFunction Max(ColumnExpression expression, AggregateType type = AggregateType.None)
        {
            return new MaxFunction(expression, type);
        }

        public static MinFunction Min(IValueExpression expression, AggregateType type = AggregateType.None)
        {
            return new MinFunction(expression, type);
        }

        public static MinFunction Min(ColumnExpression expression, AggregateType type = AggregateType.None)
        {
            return new MinFunction(expression, type);
        }

        public static CountFunction Count(IValueExpression expression, AggregateType type = AggregateType.None)
        {
            return new CountFunction(expression, type);
        }

        public static CountFunction Count(ColumnExpression expression, AggregateType type = AggregateType.None)
        {
            return new CountFunction(expression, type);
        }

        public static RoundFunction Round(IValueExpression expression, IIntegerExpression decimals)
        {
            return new RoundFunction(expression, decimals);
        }

        public static RoundFunction Round(ColumnExpression expression)
        {
            return Round(expression, 0);
        }

        public static RoundFunction Round(ColumnExpression expression, IntegerExpression decimals)
        {
            return new RoundFunction(expression, decimals);
        }

        public static CastFunction Cast(IValueExpression expression, string targetType)
        {
            return new CastFunction(expression, targetType);
        }

        /// <summary>
        /// The Extract() function extracts parts from a date
        /// </summary>
        public static ExtractFunction Extract(IValueExpression dateTime, ExtractType extractType)
        {
            return new ExtractFunction(dateTime, extractType);
        }

        public static SinFunction Sin(INumericExpression number)
        {
            return new SinFunction(number);
        }

        public static SinFunction Sin(NumericExpression number)
        {
            return new SinFunction(number);
        }

        public static CosFunction Cos(INumericExpression number)
        {
            return new CosFunction(number);
        }

        public static CosFunction Cos(NumericExpression number)
        {
            return new CosFunction(number);
        }

        public static TanFunction Tan(INumericExpression number)
        {
            return new TanFunction(number);
        }

        public static TanFunction Tan(NumericExpression number)
        {
            return new TanFunction(number);
        }

        public static AbsFunction Abs(INumericExpression number)
        {
            return new AbsFunction(number);
        }

        public static AbsFunction Abs(NumericExpression number)
        {
            return new AbsFunction(number);
        }

        public static SignFunction Sign(INumericExpression number)
        {
            return new SignFunction(number);
        }

        public static SignFunction Sign(NumericExpression number)
        {
            return new SignFunction(number);
        }

        public static PadFunction PadLeft(IStringExpression text, IntegerExpression length,
            StringExpression paddingText = null)
        {
            return new PadFunction(text, PaddingType.Left, length, paddingText);
        }

        public static PadFunction PadLeft(StringExpression text, IntegerExpression length,
            StringExpression paddingText = null)
        {
            return new PadFunction(text, PaddingType.Left, length, paddingText);
        }

        public static PadFunction PadRight(IStringExpression text, IntegerExpression length,
            StringExpression paddingText = null)
        {
            return new PadFunction(text, PaddingType.Right, length, paddingText);
        }

        public static PadFunction PadRight(StringExpression text, IntegerExpression length,
            StringExpression paddingText = null)
        {
            return new PadFunction(text, PaddingType.Right, length, paddingText);
        }

        public static TrimFunction Trim(StringExpression text)
        {
            return new TrimFunction(text);
        }

        public static TrimFunction Trim(IStringExpression text)
        {
            return new TrimFunction(text);
        }

        public static TrimFunction Trim(IStringExpression text, StringExpression trimText)
        {
            return new TrimFunction(text, trimText);
        }

        public static TrimFunction Trim(StringExpression text, StringExpression trimText)
        {
            return new TrimFunction(text, trimText);
        }

        public static TrimFunction TrimStart(StringExpression text)
        {
            return new TrimFunction(text, null, TrimType.Leading);
        }

        public static TrimFunction TrimStart(IStringExpression text)
        {
            return new TrimFunction(text, null, TrimType.Leading);
        }

        public static TrimFunction TrimStart(IStringExpression text, StringExpression trimText)
        {
            return new TrimFunction(text, trimText, TrimType.Leading);
        }

        public static TrimFunction TrimStart(StringExpression text, StringExpression trimText)
        {
            return new TrimFunction(text, trimText, TrimType.Leading);
        }

        public static TrimFunction TrimEnd(IStringExpression text, StringExpression trimText)
        {
            return new TrimFunction(text, trimText, TrimType.Trailing);
        }

        public static TrimFunction TrimEnd(StringExpression text, StringExpression trimText)
        {
            return new TrimFunction(text, trimText, TrimType.Trailing);
        }

        public static LowerFunction Lower(IStringExpression text)
        {
            return new LowerFunction(text);
        }

        public static LowerFunction Lower(StringExpression text)
        {
            return new LowerFunction(text);
        }

        public static UpperFunction Upper(IStringExpression text)
        {
            return new UpperFunction(text);
        }

        public static UpperFunction Upper(StringExpression text)
        {
            return new UpperFunction(text);
        }

        public static ReplaceFunction Replace(IStringExpression text, StringExpression oldText,
            StringExpression newText)
        {
            return new ReplaceFunction(text, oldText, newText);
        }

        public static ReplaceFunction Replace(StringExpression expression, StringExpression oldText,
            StringExpression newText)
        {
            return new ReplaceFunction(expression, oldText, newText);
        }

        public static ReverseFunction Reverse(IStringExpression text)
        {
            return new ReverseFunction(text);
        }

        public static ReverseFunction Reverse(StringExpression text)
        {
            return new ReverseFunction(text);
        }

        public static LengthFunction Length(StringExpression text)
        {
            return new LengthFunction(text);
        }

        public static LengthFunction Length(IStringExpression text)
        {
            return new LengthFunction(text);
        }

        public static SubStringFunction SubString(IStringExpression text, IntegerExpression position,
            IntegerExpression length)
        {
            return new SubStringFunction(text, position, length);
        }

        public static SubStringFunction SubString(IStringExpression text, IntegerExpression position)
        {
            return new SubStringFunction(text, position);
        }

        public static SubStringFunction SubString(StringExpression text, IntegerExpression position,
            IntegerExpression length)
        {
            return new SubStringFunction(text, position, length);
        }

        public static SubStringFunction SubString(StringExpression text, IntegerExpression position)
        {
            return new SubStringFunction(text, position);
        }

        public static LeftFunction Left(IStringExpression text, IntegerExpression length)
        {
            return new LeftFunction(text, length);
        }

        public static LeftFunction Left(StringExpression text, IntegerExpression length)
        {
            return new LeftFunction(text, length);
        }

        public static RightFunction Right(IStringExpression text, IntegerExpression length)
        {
            return new RightFunction(text, length);
        }

        public static RightFunction Right(StringExpression text, IntegerExpression length)
        {
            return new RightFunction(text, length);
        }

        public static ConcatFunction Concat(IStringExpression text, params IStringExpression[] texts)
        {
            var lst = texts.ToList();
            lst.Insert(0, text);
            return new ConcatFunction(lst);
        }

        public static ConcatFunction Concat(StringExpression text, params StringExpression[] texts)
        {
            var lst = texts.ToList<IStringExpression>();
            lst.Insert(0, text);
            return new ConcatFunction(lst);
        }

        public static NvlFunction Nvl(IValueExpression value, ConstantExpression then, ConstantExpression @default)
        {
            return new NvlFunction(value, then, @default);
        }

        public static NvlFunction Nvl(IValueExpression value, IValueExpression @default)
        {
            return new NvlFunction(value, @default);
        }

        public static NvlFunction Nvl(IValueExpression value, StringExpression @default)
        {
            return new NvlFunction(value, @default);
        }

        public static NvlFunction Nvl(StringExpression value, StringExpression @default)
        {
            return new NvlFunction(value, @default);
        }

        public static NvlFunction Nvl(StringExpression value, StringExpression then, StringExpression @default)
        {
            return new NvlFunction(value, then, @default);
        }

        public static GroupExpression And(ILogicalExpression left, ILogicalExpression right)
        {
            return new GroupExpression(left, right, GroupOperator.And);
        }

        public static GroupExpression Or(ILogicalExpression left, ILogicalExpression right)
        {
            return new GroupExpression(left, right, GroupOperator.Or);
        }
        public static LikeExpression StartWith(IValueExpression value, string pattern)
        {
            return new LikeExpression(value, $"{pattern}%");
        }
        public static LikeExpression EndWith(IValueExpression value, string pattern)
        {
            return new LikeExpression(value, $"%{pattern}");
        }
        public static LikeExpression Contains(IValueExpression value, string pattern)
        {
            return new LikeExpression(value, $"%{pattern}%");
        }
        public static LikeExpression Like(IValueExpression value, StringExpression pattern)
        {
            return new LikeExpression(value, pattern);
        }

        public static IntersectionStatement Intersect(IDataSetStatement left, IDataSetStatement right)
        {
            return new IntersectionStatement(left, right);
        }

        public static MinusStatement Minus(IDataSetStatement left, IDataSetStatement right)
        {
            return new MinusStatement(left, right);
        }


        public static UnionStatement Union(IDataSetStatement left, IDataSetStatement right,
            UnionType type = UnionType.Distinct)
        {
            return new UnionStatement(left, right, type);
        }

        public static UnionStatement UnionAll(IDataSetStatement left, IDataSetStatement right)
        {
            return new UnionStatement(left, right, UnionType.All);
        }

        public static ExistsExpression Exists(IDataSetStatement statement)
        {
            return new ExistsExpression(statement);
        }

        public static T Tag<T>(this T self, object tag) where T : ISqlObject
        {
            self.Tag = tag;
            return self;
        }

        #region [Select]

        public static IKeySelect Select(params SelectElement[] columns)
        {
            return SqlBuilder.Select(columns);
        }

        public static IKeySelect Select<T>(T element) where T : IValueExpression
        {
            return SqlBuilder.Select(new SelectElement(element));
        }

        public static IKeySelect Select<T1, T2>(T1 element1, T2 element2)
            where T1 : IValueExpression
            where T2 : IValueExpression
        {
            return SqlBuilder.Select(
                new SelectElement(element1),
                new SelectElement(element2)
            );
        }

        public static IKeySelect Select<T1, T2, T3>(T1 element1, T2 element2, T3 element3)
            where T1 : IValueExpression
            where T2 : IValueExpression
            where T3 : IValueExpression
        {
            return SqlBuilder.Select(
                new SelectElement(element1),
                new SelectElement(element2),
                new SelectElement(element3)
            );
        }

        public static IKeySelect Select<T1, T2, T3, T4>(T1 element1, T2 element2, T3 element3, T4 element4)
            where T1 : IValueExpression
            where T2 : IValueExpression
            where T3 : IValueExpression
            where T4 : IValueExpression
        {
            return SqlBuilder.Select(
                new SelectElement(element1),
                new SelectElement(element2),
                new SelectElement(element3),
                new SelectElement(element4)
            );
        }

        #endregion
    }
}